/*
 * yauosk - Yet Another Useless Operating System Kernel
 *
 * Copyright (c) 2009-2010 Matteo Cicuttin
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 * derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * All this stuff is temporary and is only needed to have a working malloc
 * for the initial development
 */

#include <malloc.h>
#include <sys/types.h>
#include <arch/machine.h>

#define	INITIAL_PAGE_DIR	0x80000

/* Identity mapping for the 0x00000000-0x000FFFFF range */
#define FIRST_MEG_TABLE		0x81000

/* Map 4 Megs starting at 0xC0000000 to 0x00100000 */
#define	KERNEL_TABLE		0x82000

/* Map 16 Megs starting at 0xD0000000 to 0x00200000. This range is used by the
 * temporary malloc() implementation 
 */
#define MALLOC_AREA_TABLES	0x83000

#define IOAPIC_MAP			0x88000

struct pt_entry {
	uint	pg_present : 1;
	uint	pg_read_write : 1;
	uint	pg_user_supervisor : 1;
	uint	pg_reserved_1 : 2;
	uint	pg_accessed : 1;
	uint	pg_dirty : 1;
	uint	pg_reserved_2 : 2;
	uint	pg_avail : 3;
	uint	pg_pfa : 20;
};

/* Page table entries and page directory entries have the same format */
typedef struct pt_entry pd_entry_t;
typedef struct pt_entry pt_entry_t;

static pd_entry_t *initpd;

static void pmap_dump_page_dir(void);

void
pmap_init(void)
{
	uint i, start_page;
	pt_entry_t *malloctab, *apictab;
	
	malloctab = (pt_entry_t *) MALLOC_AREA_TABLES;
	initpd = (pd_entry_t *) INITIAL_PAGE_DIR;
	start_page = MALLOC_BASE >> 12;
	
	/* Prepare page tables */
	
	for (i=0; i < MALLOC_PAGES; i++)
	{
		malloctab[i].pg_present = 1;
		malloctab[i].pg_read_write = 1;
		malloctab[i].pg_pfa = start_page;
	}
	
	/* Install them in the page directory */
	for (i = 0; i < MALLOC_PAGES/1024; i++)
	{
		initpd[(MALLOC_VIRTUAL >> 22) + i].pg_present = 1;
		initpd[(MALLOC_VIRTUAL >> 22) + i].pg_read_write = 1;
		initpd[(MALLOC_VIRTUAL >> 22) + i].pg_pfa =
			(MALLOC_AREA_TABLES >> 12) + i;
	}
	
	/* Map IOAPIC */
	apictab = (pt_entry_t *) IOAPIC_MAP;
	initpd[0x3fb].pg_present = 1;
	initpd[0x3fb].pg_read_write = 1;
	initpd[0x3fb].pg_pfa = IOAPIC_MAP >> 12;
	for (i = 0; i < 1024; i++)
	{
		apictab[i].pg_present = 1;
		apictab[i].pg_read_write = 1;
		apictab[i].pg_pfa = 0xFEC00 + i;
	}
	
	pmap_dump_page_dir();
}

static void
pmap_dump_page_dir(void)
{
	int i;
	printf(" *** Page directory dump BEGIN ***\n");
	for (i = 0; i < 1024; i++)
	{
		if (!initpd[i].pg_present)
			continue;
		
		printf("Entry %d: page table address: %x, RW: %d, US: %d, A: %d, D: %d\n",
				i, initpd[i].pg_pfa << 12, initpd[i].pg_read_write,
			    initpd[i].pg_user_supervisor, initpd[i].pg_accessed,
			    initpd[i].pg_dirty);
	}
	printf(" *** Page directory dump END ***\n");
}
